#include <iostream>

using namespace std;

//宏定义实现一个函数(存在缺陷)
#define ADD(x, y) x+y
//解决缺陷
#define Max(a, b) (a)>(b)?(a):(b)

//该写法没有任何效果，编译器将其视作普通函数的声明
inline void func(int);

void func(int a) {
    cout << a << endl;
}

//内联函数的声明
inline int func(int x, int y) {
    return x + y;
}

/**
 * 内联函数:
 * 1、在c语言中我们经常把一些短并且执行频繁的计算写成宏，而不是函数，这样做的理由是为了执行效率，宏可以避免函数调用的开销，这些都由预处理来完成。
 * 2、但是使用宏替代函数可能出现一些问题: 见 #define ADD。而解决的方式就是给每个变量都加上()，但是这样就写得有些繁琐了。
 * 3、为了保持预处理宏的效率又增加安全性，而且还能像一般成员函数那样可以在类里访问自如，c++引入了内联函数(inline function)。
 * 4、内联函数为了继承宏函数的效率，没有函数调用时的开销，然后又可以像普通函数那样，可以进行参数、返回值类型的安全检查，又可以作为成员函数。
 *    TIPS: 编译器将会检查函数参数列表使用是否正确，并返回值(进行必要的转换)。这些是预处理器无法完成的。
 *
 * 基本概念:
 * 1、在c++中，预定义宏的概念可以使用内联函数来实现，而"内联函数本身也是一个真正的函数"。内联函数具有普通函数的所有行为。
 *   唯一不同之处在于内联函数会在适当的地方像预定义宏一样展开，所以不需要函数调用的开销。因此应该不使用宏，使用内联函数。
 * 2、在普通函数(非成员函数)函数前面加上inline关键字使之成为内联函数。但是必须注意必须函数的声明和实现必须在一起，否则编译器将它作为普通函数来对待。
 *
 * 注意事项:
 * 1、C++中推荐使用内联函数替代宏代码片段
 * 2、内联函数在最终生成的代码中是没有定义的，C++编译器直接将函数体插入在函数调用的地方，因此内联函数没有普通函数调用时的额外开销(压栈，跳转，返回)
 * 3、因为内联函数在最终生成的代码中是没有定义的，所以内联函数的"作用域"可以理解为"只在定义的文件内可以使用"。
 *    假如在a.cpp中定义了inline int func(int a){return ++a;}，
 *    如果在b.c中需要调用func函数则在b.cpp中需要重新定义内联函数inline int func(int a){return ++a;}
 * 4、inline只是对编译器的一个内联请求，c++内联编译会有一些限制，以下情况编译器可能考虑不会将函数进行内联编译：
 *   (1)存在任何形式的循环语句  (2)存在过多的条件判断语句  (3)函数体过于庞大  (4)对函数进行取址操作
 *    因此，内联仅仅只是给编译器一个建议，编译器不一定会接受这种建议，如果你没有将函数声明为内联函数，那么编译器也可能将此函数做内联编译。
 *    一个好的编译器将会内联小的、简单的函数。
 */
int main() {
    //因为宏定义在预处理的时候是文本替换，所以 ADD(10, 20) * 10 被展开后就变成了 10+20*10
    cout << ADD(10, 20) * 10 << endl; //cout << 10+20*10 << endl;
    int ret;
    ret = Max(10 + 30, 20);//ret = (10+30)>(20)?(10+30):(20);
    cout << ret << endl;

    func(10);

    //在代码编写的阶段就可以进行类型的检查，这是宏定义做不到的
    //func("hello", 10);
    cout << func(10, 20) * 10 << endl; //cout << (10+20)*10
    return 0;
}
